/*
 * Copyright (c) 2025 Li Auto Inc. and its affiliates
 * Licensed under the Apache License, Version 2.0(the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <syslog.h>

#include "veth.h"
#include "veth_internal.h"
#include "sim_tapdev.h"
#include "sim_port_adapt.h"
#include "veth_adapter.h"
#include "ethif_cbk.h"
#if defined(VCOS_MODULE_CONFIG_DET) && (VCOS_MODULE_CONFIG_DET == 1)
#include "Det.h"
#else
static inline void det_report_error(uint16 module_id, uint8 instance_id, uint8 api_id, uint8 error_id)
{
    return;
}
#endif

#define ETH_MEM_ALIGNMENT 4 /* Align Bytes as required */
#define ETH_ALLOC_ALIGNED(size) aligned_alloc(ETH_MEM_ALIGNMENT, (size))

static const veth_config_type *veth_config_set_ptr;
static veth_ctrl_status_type *veth_ctrl_status[OS_CORE_CNT];
static sim_port_mutex_t mutex_eth_transmit = NULL;

static veth_buff_type *alloc_eth_buffers(const veth_core_ctrl_config_type *config);
static veth_core_ctrl_config_type *veth_get_ctrl_config_ptr(const uint8 ctrl_idx);
static veth_ctrl_status_type *veth_get_ctrl_status_ptr(const uint8 ctrl_idx);
static void veth_release_tx_buf(const uint8 ctrl_idx, const eth_buf_idx_type buf_idx);

void veth_print(int priority, const char *fmt, ...)
{
#if (CONFIG_SIM_ETH_DEBUG == 1)
    va_list args;
    va_start(args, fmt);
    vsyslog(priority, fmt, args);
    va_end(args);
#else
    (void)priority;
    (void)fmt;
#endif
}

static veth_buff_type *alloc_eth_buffers(const veth_core_ctrl_config_type *config)
{
    veth_buff_type *buff = (veth_buff_type *)malloc(sizeof(veth_buff_type));

    if (NULL == buff) {
        return NULL;
    }

    buff->eth_tx_buff_table_ptr = ETH_ALLOC_ALIGNED(config->eth_tx_buf_total * /* Allocate transmission status table */
                            sizeof(veth_tx_buf_tables_type));
    if (NULL == buff->eth_tx_buff_table_ptr) {
        free(buff);
        return NULL;
    }
    memset(buff->eth_tx_buff_table_ptr, 0, config->eth_tx_buf_total * sizeof(veth_tx_buf_tables_type));

    buff->eth_rx_buff_table_ptr = ETH_ALLOC_ALIGNED(config->eth_rx_buf_total * /* Allocate reception status table */
                            sizeof(veth_rx_buf_tables_type));
    if (NULL == buff->eth_rx_buff_table_ptr) {
        free(buff->eth_tx_buff_table_ptr);
        free(buff);
        return NULL;
    }
    memset(buff->eth_rx_buff_table_ptr, 0, config->eth_rx_buf_total * sizeof(veth_rx_buf_tables_type));

    buff->eth_tx_buffer_ptr = ETH_ALLOC_ALIGNED(config->eth_tx_buf_total * config->eth_ctrl_tx_buf_len_byte);
    if (NULL == buff->eth_tx_buffer_ptr) {
        free(buff->eth_tx_buff_table_ptr);
        free(buff->eth_rx_buff_table_ptr);
        free(buff);
        return NULL;
    }

    buff->eth_rx_buffer_ptr = ETH_ALLOC_ALIGNED(config->eth_rx_buf_total * /* Allocate receive data buffer */
                        config->eth_ctrl_rx_buf_len_byte);
    if (NULL == buff->eth_rx_buffer_ptr) {
        free(buff->eth_tx_buff_table_ptr);
        free(buff->eth_rx_buff_table_ptr);
        free(buff->eth_tx_buffer_ptr);
        free(buff);
        return NULL;
    }

    return buff;
}

static veth_core_ctrl_config_type *veth_get_ctrl_config_ptr(const uint8 ctrl_idx)
{
    uint8 core_id;
    uint8 core_ctrl_idx;
    veth_core_config_type *eth_local_core_cfg_ptr = NULL;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;

    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == veth_config_set_ptr) {
        return NULL_PTR;
    }
    eth_local_core_cfg_ptr = veth_config_set_ptr->veth_core_add[core_id];
    core_ctrl_idx = veth_config_set_ptr->veth_node_idxmap_ptr[ctrl_idx];
    if (core_ctrl_idx > eth_local_core_cfg_ptr->veth_max_controllers) {
        return NULL_PTR;
    }

    eth_local_ctrl_cfg_ptr = eth_local_core_cfg_ptr->veth_core_ctrl_ptr;
    eth_local_ctrl_cfg_ptr = &(eth_local_ctrl_cfg_ptr[core_ctrl_idx]);
    if (eth_local_ctrl_cfg_ptr->eth_ctrl_idx != ctrl_idx) {
        return NULL_PTR;
    }
    return eth_local_ctrl_cfg_ptr;
}

static void veth_release_tx_buf(const uint8 ctrl_idx, const eth_buf_idx_type buf_idx)
{
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;
    veth_tx_buf_tables_type *curr_tx_buff_table_ptr = NULL;

    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);

    curr_tx_buff_table_ptr = &(eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buff_table_ptr[buf_idx]);
    curr_tx_buff_table_ptr->frame_tx_initiated = 0;
    curr_tx_buff_table_ptr->tx_confirm_req = 0;
    curr_tx_buff_table_ptr->buff_status = 0;
    curr_tx_buff_table_ptr->frame_tx_sent = 0;
}

static veth_ctrl_status_type *veth_get_ctrl_status_ptr(const uint8 ctrl_idx)
{
    uint8 core_id;
    uint8 core_cntrl_idx;
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;

    core_id = (uint8)up_cpu_index(); /* Get the current core Id */
    if (NULL_PTR == veth_config_set_ptr) {
        return NULL_PTR;
    }
    core_cntrl_idx = veth_config_set_ptr->veth_node_idxmap_ptr[ctrl_idx];
    eth_local_ctrl_status_ptr = veth_ctrl_status[core_id];
    eth_local_ctrl_status_ptr = &(eth_local_ctrl_status_ptr[core_cntrl_idx]);
    return eth_local_ctrl_status_ptr;
}

void veth_init(const veth_config_type *veth_config_ptr)
{
    uint8 coreid;
    uint8 ctrl_idx;
    uint8 ctrl_num;
    Std_ReturnType ret_value;
    const veth_core_config_type *eth_local_core_cfg_ptr = NULL;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;

#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (NULL_PTR == veth_config_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_INIT, vETH_E_PARAM_POINTER);
        return;
    }
#endif

    coreid = (uint8)up_cpu_index(); /* Get the current coreid */
    eth_local_core_cfg_ptr = veth_config_ptr->veth_core_add[coreid]; /* Get configuration of the current core */
#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (NULL == eth_local_core_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_INIT, vETH_E_CORE_NOT_CONFIGURED);
        return;
    }
#endif
    veth_config_set_ptr = veth_config_ptr;
    ctrl_num = eth_local_core_cfg_ptr->veth_max_controllers;
    veth_ctrl_status[coreid] = (veth_ctrl_status_type *)malloc(ctrl_num * sizeof(veth_ctrl_status_type));
    if (NULL == veth_ctrl_status[coreid]) {
        veth_print(LOG_DEBUG, "[vEth]Failed to alloc memory for coreid %d\n", coreid);
        return;
    }
    for (ctrl_idx = 0; ctrl_idx < ctrl_num; ctrl_idx++) {
        veth_ctrl_status_type *ctrl_status;

        ctrl_status = &veth_ctrl_status[coreid][ctrl_idx]; /* Initialize state structure */
        eth_local_ctrl_cfg_ptr = &(eth_local_core_cfg_ptr->veth_core_ctrl_ptr[ctrl_idx]);

        memset(&ctrl_status->eth_statistics_counters, 0, sizeof(veth_statistics_counter_type));

        ctrl_status->eth_run_time_opertn_data.eth_controller_mode = ETH_MODE_DOWN;
        ctrl_status->eth_run_time_opertn_data.preveth_controller_mode = ETH_MODE_DOWN;
        ctrl_status->eth_run_time_opertn_data.veth_init_status = ETH_STATE_UNINIT;
        ctrl_status->eth_run_time_opertn_data.curr_tx_idx = ctrl_idx;
        ctrl_status->eth_run_time_opertn_data.confirm_tx_buf_idx = 0;
        memcpy(ctrl_status->eth_run_time_opertn_data.eth_unicast_mac_address, eth_local_ctrl_cfg_ptr->eth_mac_address,
            vETH_MACADDRESS_LEN);

        ctrl_status->eth_buff_ptr = alloc_eth_buffers(eth_local_ctrl_cfg_ptr);
        if (NULL_PTR == ctrl_status->eth_buff_ptr) {
            veth_print(LOG_DEBUG, "[vEth]Failed to alloc EthBuff memory for ctrl_idx %d\n", ctrl_idx);
            return;
        }
        if ((ETH_ENABLE == eth_local_ctrl_cfg_ptr->tx_int_enable) &&
                                        (ETH_ENABLE == eth_local_ctrl_cfg_ptr->rx_int_enable)) {
            ret_value = tap_init(eth_local_ctrl_cfg_ptr, ctrl_status, veth_tx_done_fun, veth_rx_done_fun);
        } else {
            ret_value = tap_init(eth_local_ctrl_cfg_ptr, ctrl_status, NULL, NULL);
        }

        if (E_OK != ret_value) {
            veth_print(LOG_DEBUG, "[vEth]Failed to create tap\n");
            return;
        }

        if (SIM_PORT_ERROR == sim_port_mutex_init(&mutex_eth_transmit)) {
            veth_print(LOG_DEBUG, "[vEth]Failed to initialise mutex.\n");
            return;
        }
        ctrl_status->eth_run_time_opertn_data.veth_init_status = ETH_STATE_INIT;
        ctrl_status->eth_run_time_opertn_data.eth_controller_mode = ETH_MODE_ACTIVE;
    }
    return;
}

void veth_tx_done_fun(const uint8 ctrl_idx)
{
    up_trigger_irq(ISR_ETHTX_ID, 1<<ETH_COREID);
}

void veth_rx_done_fun(const uint8 ctrl_idx)
{
    up_trigger_irq(ISR_ETHRX_ID, 1<<ETH_COREID);
}

static inline uint8 veth_incr_tx_buf_idx(const uint8 tx_buf_idx, const uint8 eth_tx_buf_total)
{
    return ((tx_buf_idx + 1U) % (eth_tx_buf_total));
}

static inline boolean veth_is_broadcast_address(const uint8 *const mac_addr)
{
    boolean ret_val;

    if ((mac_addr[0] == 0xFFU) && (mac_addr[1] == 0xFFU) && (mac_addr[2] == 0xFFU) &&
        (mac_addr[3] == 0xFFU) && (mac_addr[4] == 0xFFU) && (mac_addr[5] == 0xFFU)) {
        ret_val = TRUE; /* MAC address is a broadcase address. */
    } else {
        ret_val = FALSE;
    }
    return ret_val;
}

BufReq_ReturnType veth_provide_tx_buffer(const uint8 ctrl_idx, eth_buf_idx_type *const bufidx_ptr,
                                uint8 **const buf_ptr, uint16 *const lenbyte_ptr)
{
    uint16 tx_buf_length_config;
    uint16 payload_len;
    BufReq_ReturnType buffer_status = BUFREQ_E_BUSY;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;
    uint8 *tx_buff_base_ptr = NULL;
    veth_tx_buf_tables_type *curr_tx_buff_table_ptr = NULL;

/* Validation of input parameters */
#if (vETH_DEV_ERROR_DETECT == STD_ON)
    uint8 core_id;

    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == bufidx_ptr || NULL_PTR == buf_ptr || NULL_PTR == lenbyte_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_PROVIDETXBUFFER, vETH_E_PARAM_POINTER);
        return BUFREQ_E_NOT_OK;
    }
    if (NULL_PTR == veth_ctrl_status[core_id]) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_PROVIDETXBUFFER,
                    vETH_E_CORE_NOT_CONFIGURED);
        return BUFREQ_E_NOT_OK;
    }
    if (ctrl_idx >= vETH_MAX_CONTROLLERS) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_PROVIDETXBUFFER,
                    vETH_E_CORE_NOT_CONFIGURED);
        return BUFREQ_E_NOT_OK;
    }
#endif

    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx); /* Get the configuration of this controller */
#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (NULL_PTR == eth_local_ctrl_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_PROVIDETXBUFFER, vETH_E_INV_CTRL_IDX);
        return BUFREQ_E_NOT_OK;
    }
#endif
    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (ETH_MODE_DOWN == eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_controller_mode) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_PROVIDETXBUFFER, vETH_E_INV_MODE);
        return BUFREQ_E_NOT_OK;
    }
#endif

    tx_buf_length_config = eth_local_ctrl_cfg_ptr->eth_ctrl_tx_buf_len_byte; /* Get configured buffer length */

    sim_port_mutex_lock(mutex_eth_transmit);

    curr_tx_buff_table_ptr = &(eth_local_ctrl_status_ptr->eth_buff_ptr
                    ->eth_tx_buff_table_ptr[eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_tx_idx]);

    if ((curr_tx_buff_table_ptr->buff_status == 1) && (curr_tx_buff_table_ptr->frame_tx_initiated == 1) &&
        (curr_tx_buff_table_ptr->tx_confirm_req == 0) && (curr_tx_buff_table_ptr->frame_tx_sent == 1)) {
        curr_tx_buff_table_ptr->frame_tx_initiated = 0; /* Reset buffer state */
        curr_tx_buff_table_ptr->buff_status = 0;
        curr_tx_buff_table_ptr->frame_tx_sent = 0;
        if (eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx ==
            eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_tx_idx) {
            eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx =
                veth_incr_tx_buf_idx(eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx,
                        eth_local_ctrl_cfg_ptr->eth_tx_buf_total);
        }
    }
    payload_len = tx_buf_length_config - ((uint16)(vETH_FRAMEHEADER_LENGTH + vETH_FRAMECHKSUM_LENGTH));
    if (tx_buf_length_config <= ((uint16)(vETH_FRAMEHEADER_LENGTH + vETH_FRAMECHKSUM_LENGTH))) {
        *lenbyte_ptr = 0;
        buffer_status = BUFREQ_E_OVFL;
    } else if ((uint16)(*lenbyte_ptr) > payload_len) {
        *lenbyte_ptr = tx_buf_length_config - ((uint16)(vETH_FRAMEHEADER_LENGTH + vETH_FRAMECHKSUM_LENGTH));
        buffer_status = BUFREQ_E_OVFL;
    } else {
        if (curr_tx_buff_table_ptr->buff_status == 0) { /* 分配空闲buffer */
            *bufidx_ptr = eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_tx_idx;
            curr_tx_buff_table_ptr->frame_tx_initiated = 0;
            curr_tx_buff_table_ptr->tx_confirm_req = 0;
            curr_tx_buff_table_ptr->buff_status = 1;
            curr_tx_buff_table_ptr->frame_tx_sent = 0;

            tx_buff_base_ptr = &(eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buffer_ptr[0]);
            *buf_ptr =
                tx_buff_base_ptr +
                (uint32)(eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_tx_idx) * (tx_buf_length_config) +
                vETH_FRAMEHEADER_LENGTH;

            eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_tx_idx =
                veth_incr_tx_buf_idx(eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_tx_idx,
                        eth_local_ctrl_cfg_ptr->eth_tx_buf_total);
            buffer_status = BUFREQ_OK;
        }
    }
    sim_port_mutex_unlock(mutex_eth_transmit);
    return buffer_status;
}

Std_ReturnType veth_transmit(const uint8 ctrl_idx, const eth_buf_idx_type buf_idx, const eth_frame_type frame_type,
                const boolean tx_confirmation, const uint16 len_byte, const uint8 *const phys_addr_ptr)
{
    uint16 tx_buf_length_config;
    uint8 loop_count;
    uint32 tx_length;
    Std_ReturnType ret;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;
    uint8 *tx_buff_base_ptr = NULL;
    uint8 *tx_buffer_address = NULL;

#if (vETH_DEV_ERROR_DETECT == STD_ON)
    uint8 core_id;

    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == veth_ctrl_status[core_id]) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_TRANSMIT, vETH_E_CORE_NOT_CONFIGURED);
        return E_NOT_OK;
    }
    if (ctrl_idx >= vETH_MAX_CONTROLLERS) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_TRANSMIT, vETH_E_CORE_NOT_CONFIGURED);
        return E_NOT_OK;
    }
#endif

    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx); /* Get the configuration of this controller */
#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (NULL_PTR == eth_local_ctrl_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_TRANSMIT, vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
#endif
    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (ETH_MODE_DOWN == eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_controller_mode) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_TRANSMIT, vETH_E_INV_MODE);
        /* Releasing the buffer makes sense only if the core id and ctrl_idx are correct */
        veth_release_tx_buf(ctrl_idx, buf_idx);
        return E_NOT_OK;
    }
    if (NULL_PTR == phys_addr_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_TRANSMIT, vETH_E_PARAM_POINTER);
        veth_release_tx_buf(ctrl_idx, buf_idx);
        return E_NOT_OK;
    }
#endif

    tx_buf_length_config = eth_local_ctrl_cfg_ptr->eth_ctrl_tx_buf_len_byte;
    tx_buff_base_ptr = &(eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buffer_ptr[0]);
    tx_buffer_address = tx_buff_base_ptr + (uint32)buf_idx * tx_buf_length_config;

    for (loop_count = 0; loop_count < vETH_MACADDRESS_LEN; loop_count++) {
        tx_buffer_address[loop_count] = phys_addr_ptr[loop_count];
    }

    veth_get_phys_addr(ctrl_idx, tx_buffer_address + vETH_FRAME_SRCADDR_POS);
    /* Fill the Frame Type in TX Buffer */
    tx_buffer_address[vETH_FRAME_TYPE_POS_MSB] = (uint8)((frame_type >> 8) & vETH_BYTE_MASK);
    tx_buffer_address[vETH_FRAME_TYPE_POS_LSB] = (uint8)(frame_type & vETH_BYTE_MASK);
    /* LenByte plus the length of the frame header */
    tx_length = (uint32)(len_byte + vETH_FRAMEHEADER_LENGTH);

    if (TRUE == tx_confirmation) { /*处理 txconfirmation*/
        eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buff_table_ptr[buf_idx].tx_confirm_req = 1;
    } else {
        eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buff_table_ptr[buf_idx].tx_confirm_req = 0;
    }

    eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buff_table_ptr[buf_idx].length = tx_length;
    /* 帧填充完毕*/
    eth_local_ctrl_status_ptr->eth_buff_ptr->eth_tx_buff_table_ptr[buf_idx].frame_tx_initiated = 1;

    if (NULL != tap_send_sem) {
        if (SIM_PORT_SUCCESS != sim_port_sem_post(tap_send_sem)) { /* Trigger send thread */
            veth_print(LOG_DEBUG, "Trigger: Post failed!\n");
        }
    }

    ret = E_OK;
    return ret;
}

void veth_tx_ctrl0_irq_hdlr(void)
{
    uint8 ctrl_idx;

    ctrl_idx = 0;
    veth_tx_confirmation(ctrl_idx);
}

void veth_rx_ctrl0_irq_hdlr(void)
{
    uint8 ctrl_idx;

    ctrl_idx = 0;
    veth_receive(ctrl_idx);
}

void veth_tx_confirmation(uint8 ctrl_idx)
{
    eth_buf_idx_type buf_idx;
    uint8 tx_buf_total;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;
    veth_tx_buf_tables_type *curr_tx_buff_table_ptr = NULL;

    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx);
    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
    tx_buf_total = eth_local_ctrl_cfg_ptr->eth_tx_buf_total;
    for (buf_idx = 0; buf_idx < tx_buf_total; buf_idx++) {
        curr_tx_buff_table_ptr =
            &(eth_local_ctrl_status_ptr->eth_buff_ptr
                ->eth_tx_buff_table_ptr[eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx]);
        if ((1 == curr_tx_buff_table_ptr->buff_status) && (1 == curr_tx_buff_table_ptr->frame_tx_initiated) &&
            (1 == curr_tx_buff_table_ptr->frame_tx_sent)) {
            if (1 == curr_tx_buff_table_ptr->tx_confirm_req) {
                ethif_txconfirmation(ctrl_idx, buf_idx);
                curr_tx_buff_table_ptr->tx_confirm_req = 0; /* Reset Tx confirmation request. */
            }

            curr_tx_buff_table_ptr->frame_tx_initiated = 0; /* Restore buffer unused state */
            curr_tx_buff_table_ptr->buff_status = 0;
            curr_tx_buff_table_ptr->frame_tx_sent = 0;
            veth_print(LOG_DEBUG, "[vEth]reset txbuf %d\n",
                                eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx);
            eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx = veth_incr_tx_buf_idx(
                eth_local_ctrl_status_ptr->eth_run_time_opertn_data.confirm_tx_buf_idx, tx_buf_total);
        } else {
            break;
        }
    }
}

void veth_receive(uint8 ctrl_idx)
{
    eth_buf_idx_type buf_idx;
    uint8 rx_buf_total;
    uint16 rx_length;
    uint16 rx_buf_length_config;
    uint16 frame_type;
    boolean broadcast_state;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;
    veth_rx_buf_tables_type *curr_rx_buff_table_ptr = NULL;
    uint8 *rx_buffer_address = NULL;
    uint8 *rx_buff_base_ptr = NULL;

    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx);
    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
    rx_buf_total = eth_local_ctrl_cfg_ptr->eth_rx_buf_total;
    rx_buf_length_config = eth_local_ctrl_cfg_ptr->eth_ctrl_rx_buf_len_byte;
    rx_buff_base_ptr = &(eth_local_ctrl_status_ptr->eth_buff_ptr->eth_rx_buffer_ptr[0]);

    for (buf_idx = 0; buf_idx < rx_buf_total; buf_idx++) {
        curr_rx_buff_table_ptr =
            &(eth_local_ctrl_status_ptr->eth_buff_ptr
                ->eth_rx_buff_table_ptr[eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_rx_idx]);
        if ((1 == curr_rx_buff_table_ptr->buff_status) && (1 == curr_rx_buff_table_ptr->frame_rx_initiated)) {
            rx_length = curr_rx_buff_table_ptr->length;

            rx_buffer_address = rx_buff_base_ptr + (uint32)buf_idx * rx_buf_length_config;
            frame_type = ((uint16)(((uint16)(((uint16)rx_buffer_address[vETH_FRAME_TYPE_POS_MSB])
                            << (vETH_SHIFT_8BIT))) |
                        ((uint16)rx_buffer_address[vETH_FRAME_TYPE_POS_LSB])));
            broadcast_state = veth_is_broadcast_address(&(rx_buffer_address[vETH_FRAME_DESTADDR_POS]));
            ethif_rxindication(ctrl_idx, frame_type, broadcast_state,
                    &(rx_buffer_address[vETH_FRAME_SRCADDR_POS]),
                    (uint8 *)&(rx_buffer_address[vETH_FRAME_PAYLOAD_POS]), rx_length);

            curr_rx_buff_table_ptr->buff_status = 0; /* Restore buffer unused state */
            curr_rx_buff_table_ptr->frame_rx_initiated = 0;
            veth_print(LOG_DEBUG, "[vEth]new free rxbuf is %d\n",
                                eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_rx_idx);
            eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_rx_idx =
                veth_incr_tx_buf_idx(eth_local_ctrl_status_ptr->eth_run_time_opertn_data.curr_rx_idx, rx_buf_total);

        } else {
            break;
        }
    }
}

Std_ReturnType veth_get_controller_mode(const uint8 ctrl_idx, eth_mode_type *const ctrl_mode_ptr)
{
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;

#if (vETH_DEV_ERROR_DETECT == STD_ON)
    if (NULL_PTR == ctrl_mode_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETCONTROLLERMODE,
                    vETH_E_PARAM_POINTER);
        return E_NOT_OK;
    }
    uint8 core_id;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;

    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == veth_ctrl_status[core_id]) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETCONTROLLERMODE,
                    vETH_E_CORE_NOT_CONFIGURED);
        return E_NOT_OK;
    }
    if (ctrl_idx >= vETH_MAX_CONTROLLERS) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETCONTROLLERMODE,
                    vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx);
    if (NULL_PTR == eth_local_ctrl_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETCONTROLLERMODE,
                    vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
#endif

    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
    *ctrl_mode_ptr = eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_controller_mode;
    return E_OK;
}

Std_ReturnType veth_set_controller_mode(const uint8 ctrl_idx, const eth_mode_type ctrl_mode)
{
    eth_mode_type cur_ctrl_mode;
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;

#if (vETH_DEV_ERROR_DETECT == STD_ON)
    uint8 core_id;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;

    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == veth_ctrl_status[core_id]) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETCONTROLLERMODE,
                    vETH_E_CORE_NOT_CONFIGURED);
        return E_NOT_OK;
    }
    if (ctrl_idx >= vETH_MAX_CONTROLLERS) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETCONTROLLERMODE,
                    vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
    /*获取该Ctrl的配置*/
    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx);
    if (NULL_PTR == eth_local_ctrl_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETCONTROLLERMODE,
                    vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
#endif

    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
    cur_ctrl_mode = eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_controller_mode;

    if (cur_ctrl_mode != ctrl_mode) {
        if (E_OK != tap_set_controller_mode(ctrl_idx, ctrl_mode)) {
            return E_NOT_OK;
        } else {
            eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_controller_mode = ctrl_mode;
            ethif_ctrlmode_indication(ctrl_idx, ctrl_mode);
        }
    }

    return E_OK;
}

Std_ReturnType veth_get_phys_addr(const uint8 ctrl_idx, uint8 *const phys_addr_ptr)
{
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;

#if (vETH_DEV_ERROR_DETECT == STD_ON)
    uint8 core_id;

    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;

    if (NULL_PTR == phys_addr_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETPHYADDRESS, vETH_E_PARAM_POINTER);
        return E_NOT_OK;
    }
    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == veth_ctrl_status[core_id]) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETPHYADDRESS,
                    vETH_E_CORE_NOT_CONFIGURED);
        return E_NOT_OK;
    }
    if (ctrl_idx >= vETH_MAX_CONTROLLERS) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETPHYADDRESS, vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx);
    if (NULL_PTR == eth_local_ctrl_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_GETPHYADDRESS, vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
#endif

    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
    memcpy(phys_addr_ptr, eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_unicast_mac_address, vETH_MACADDRESS_LEN);
    return E_OK;
}

Std_ReturnType veth_set_phys_addr(const uint8 ctrl_idx, const uint8 *const phys_addr_ptr)
{
    veth_ctrl_status_type *eth_local_ctrl_status_ptr = NULL;

#if (vETH_DEV_ERROR_DETECT == STD_ON)
    uint8 core_id;
    veth_core_ctrl_config_type *eth_local_ctrl_cfg_ptr = NULL;

    if (NULL_PTR == phys_addr_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETPHYSADDRESS, vETH_E_PARAM_POINTER);
        return E_NOT_OK;
    }

    core_id = (uint8)up_cpu_index();
    if (NULL_PTR == veth_ctrl_status[core_id]) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETPHYSADDRESS,
                    vETH_E_CORE_NOT_CONFIGURED);
        return E_NOT_OK;
    }
    if (ctrl_idx >= vETH_MAX_CONTROLLERS) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETPHYSADDRESS, vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }

    eth_local_ctrl_cfg_ptr = veth_get_ctrl_config_ptr(ctrl_idx);
    if (NULL_PTR == eth_local_ctrl_cfg_ptr) {
        (void)det_report_error(vETH_MODULE_ID, vETH_INSTANCE_ID, vETH_SID_SETPHYSADDRESS, vETH_E_INV_CTRL_IDX);
        return E_NOT_OK;
    }
#endif

    eth_local_ctrl_status_ptr = veth_get_ctrl_status_ptr(ctrl_idx);
    memcpy(eth_local_ctrl_status_ptr->eth_run_time_opertn_data.eth_unicast_mac_address, phys_addr_ptr, vETH_MACADDRESS_LEN);
    return E_OK;
}
